/*
 * string_util.h
 *
 *  Created on: 2008-9-25
 *      Author: fanliangliang
 */

#ifndef STRING_UTIL_H_
#define STRING_UTIL_H_

#include "config.h"
#include "lexical_cast.h"
#include <cctype>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <functional>
#include <algorithm>

BEGIN_NAMESPACE_TOXIC

using std::string;
using std::vector;
using std::deque;
using std::list;
using std::set;
using std::multiset;
using std::replace_if;
using std::bind1st;
using std::equal_to;

template <typename T>
inline void insert(vector<T>& v, const T& value) {
	v.push_back(value);
}

template <typename T, typename U>
inline void insert(vector<T>& v, const U& value) {
	v.push_back(lexical_cast<T>(value));
}

template <typename T>
inline void insert(deque<T>& d, const T& value) {
	d.push_back(value);
}

template <typename T, typename U>
inline void insert(deque<T>& v, const U& value) {
	v.push_back(lexical_cast<T>(value));
}

template <typename T>
inline void insert(list<T>& l, const T& value) {
	l.push_back(value);
}

template <typename T, typename U>
inline void insert(list<T>& v, const U& value) {
	v.push_back(lexical_cast<T>(value));
}

template <typename T>
inline void insert(set<T>& s, const T& value) {
	s.insert(value);
}

template <typename T, typename U>
inline void insert(set<T>& v, const U& value) {
	v.insert(lexical_cast<T>(value));
}

template <typename T>
inline void insert(multiset<T>& s, const T& value) {
	s.insert(value);
}

template <typename T, typename U>
inline void insert(multiset<T>& v, const U& value) {
	v.insert(lexical_cast<T>(value));
}


template <typename Container>
size_t split(Container& tokens, const string& s,
		const string& delims = " ", int limit = 0) {

    string::size_type currPos = 0, prevPos = 0, count = 0;
    while (--limit != 0 && (currPos = s.find_first_of(delims, prevPos)) != string::npos) {
        count = currPos - prevPos;
        if (count != 0) {
            insert(tokens, s.substr(prevPos, count));
        }
        prevPos = currPos + 1;
    }

    count = s.size() - prevPos;
    if (count != 0) {
    	 insert(tokens, s.substr(prevPos, count));
    }

    return tokens.size();
}

template <typename Container>
size_t split_ex(Container& tokens, const string& s,
		const string& delims = " ", int limit = 0) {

    string::size_type currPos = 0, prevPos = 0, count = 0;
    while (--limit != 0 && (currPos = s.find_first_of(delims, prevPos)) != string::npos) {
        count = currPos - prevPos;
        insert(tokens, s.substr(prevPos, count));
        prevPos = currPos + 1;
    }

    count = s.size() - prevPos;
    insert(tokens, s.substr(prevPos, count));

    return tokens.size();
}

string& trim(string& s, const string& delims = " ");
string& ltrim(string& s, const string& delims = " ");
string& rtrim(string& s, const string& delims = " ");

string trim(const string& s, const string& delims = " ");
string ltrim(const string& s, const string& delims = " ");
string rtrim(const string& s, const string& delims = " ");

string& replace(string& s, const string& oldValue, const string& newValue);
string& replace(string& s, const string& oldValue, size_t num, char c);

inline string& replace(string& s, char oldValue, char newValue) {
	replace_if(s.begin(), s.end(), bind1st(equal_to<char>(), oldValue), newValue);
	return s;
}

inline string& toLowerCase(string& s) {
	transform(s.begin(), s.end(), s.begin(), ::tolower);
	return s;
}

inline string toLowerCase(const string& s) {
	string result(s);
	return toLowerCase(result);
}

inline string& toUpperCase(string& s) {
	transform(s.begin(), s.end(), s.begin(), ::toupper);
	return s;
}

inline string toUpperCase(const string& s) {
	string result(s);
	return toUpperCase(result);
}

// tests if string 's' starts with the specified 'prefix' beginning a specified index 'pos'
bool startsWith(const string& s, const string& prefix, size_t pos = 0);

// tests if string 's' ends with the specified 'suffix'
bool endsWith(const string& s, const string& suffix);

END_NAMESPACE_TOXIC

#endif /* STRING_UTIL_H_ */
